package com.denlaku.longan.controller.impl;

import com.denlaku.longan.anno.Audit;
import com.denlaku.longan.anno.VarBy;
import com.denlaku.longan.anno.VarOp;
import com.denlaku.longan.audit.AuditVariables;
import com.denlaku.longan.controller.DataSetController;
import com.denlaku.longan.core.Current;
import com.denlaku.longan.http.Resp;
import com.denlaku.longan.http.Return;
import com.denlaku.longan.qo.DataSetQuery;
import com.denlaku.longan.qo.Query;
import com.denlaku.longan.service.DataSetFieldService;
import com.denlaku.longan.service.DataSetService;
import com.denlaku.longan.service.ObjectTagService;
import com.denlaku.longan.service.TenantMemObjPermService;
import com.denlaku.longan.util.Objects;
import com.denlaku.longan.util.SnowflakeUtils;
import com.denlaku.longan.vo.DataSet;
import com.denlaku.longan.vo.DataSetField;
import com.denlaku.longan.vo.MetaData;
import com.denlaku.longan.vo.PageBy;
import com.github.pagehelper.PageHelper;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author tianx
 */
@RestController
public class DataSetControllerImpl implements DataSetController {
	@Autowired
	private DataSetService dataSetService;

	@Autowired
	private DataSetFieldService dataSetFieldService;

	@Autowired
	private ObjectTagService objPermTagService;

    @Autowired
    private TenantMemObjPermService tenantMemObjPermService;

	@VarOp
	@Override
	@Audit(message = "add data set: {#dataSet.name}", operation = "audit.operation.addDataSet", module = "DataSet")
	public Return<Long> add(@RequestBody DataSet dataSet) {
		dataSet.setId(SnowflakeUtils.nextId());
		dataSetService.add(dataSet);
		return Resp.success(dataSet.getId());
	}
	
	@VarOp
	@Override
	@Audit(message = "update data set: {#dataSet.name}", operation = "audit.operation.updateDataSet", module = "DataSet")
	public Return<Void> update(@RequestBody DataSet dataSet) {
		dataSet.setTenantId(Current.getTenantId());
		dataSetService.update(dataSet);
		return Resp.success();
	}

	@Override
	@Audit(message = "delete data set: {#name}", operation = "audit.operation.deleteDataSet", module = "DataSet")
	public Return<Void> delete(Long id) {
		DataSet dataSet = dataSetService.getBase(Query.of(id));
		String name = Optional.ofNullable(dataSet).map(DataSet::getName).orElse(String.valueOf(id));
		AuditVariables.set("name", name);
		dataSetService.delete(Query.of(id));
		return Resp.success();
	}

	@VarBy
	@Override
	public Return<List<DataSet>> pageList(DataSetQuery query, PageBy pageBy) {
        tenantMemObjPermService.setPermTagIds(query);
		PageHelper.startPage(pageBy.getPage(), pageBy.getSize());
		List<DataSet> list = dataSetService.list(query);
		setTagName(query.getTenantId(), list);
		return Resp.success(list);
	}

	private void setTagName(Long tenantId, List<DataSet> list) {
		Set<Long> tagIds = list.stream().map(DataSet::getTagId).filter(Objects::nonNull).collect(Collectors.toSet());
		Map<Long, String> tagMap = objPermTagService.getTagNameMap(Query.of(tenantId, tagIds));
		list.forEach(ds -> ds.setTagName(tagMap.get(ds.getTagId())));
	}

	@Override
	public Return<List<DataSet>> list(DataSetQuery query) {
        tenantMemObjPermService.setPermTagIds(query);
		List<DataSet> list = dataSetService.list(query);
		if (CollectionUtils.isNotEmpty(list)) {
			list.forEach(ds -> {
				List<DataSetField> fields = dataSetFieldService.list(ds.getTenantId(), ds.getId());
				ds.setFields(fields);
			});
		}
		return Resp.success(list);
	}

	@Override
	public Return<DataSet> get(Long id) {
		DataSet dataSet = dataSetService.getCache(Query.of(id));
		return Resp.success(dataSet);
	}

	@Override
	public Return<List<MetaData>> listMetaData(@RequestBody DataSet dataSet) {
		List<MetaData> listMetaData = dataSetService.listMetaData(dataSet);
		return Resp.success(listMetaData);
	}
}
